/**
 * @file example_006.cpp
 * @author yangjian (1171267147@qq.com)
 * @brief 可配置对象工厂--原型
 * @version 0.1
 * @date 2025-07-11
 *
 * @copyright 《深入应用c++11：代码优化与工程级应用》
 *
 */

#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>

using std::cerr;
using std::function;
using std::map;
using std::shared_ptr;
using std::string;

template <typename T>
class IocContainer {
public:
    IocContainer()  = default;
    ~IocContainer() = default;

    template <typename Drived>
    void RegisterType(string key) {
        // 将构造函数转化为函数对象，实现延迟调用
        function<T*()> creator = []() -> T* {
            return new Drived();
        };
        RegisterType(key, creator);
    }

    T* Resolve(string key) {
        auto it = creatorMap_.find(key);
        if (it == creatorMap_.end()) {
            cerr << "key: " << key << " not found" << std::endl;
            return nullptr;
        }
        return it->second();
    }

    shared_ptr<T> ResolveShared(string key) {
        T* ptr = Resolve(key);
        return shared_ptr<T>(ptr);
    }

private:
    void RegisterType(string key, function<T*()> creator) {
        if (creatorMap_.find(key) != creatorMap_.end()) {
            cerr << "key: " << key << " has been registered" << std::endl;
            return;
        }
        creatorMap_[key] = creator;
    }

private:
    map<string, function<T*()>> creatorMap_;  // key与构造函数的映射
};

class Animal {
public:
    virtual ~Animal() = default;
    virtual void Speak() = 0;
};

class Dog : public Animal {
public:
    void Speak() override {
        std::cout << "Dog: 汪汪汪" << std::endl;
    }
};

class Cat : public Animal {
public:
    void Speak() override {
        std::cout << "Cat: 喵喵喵" << std::endl;
    }
};

class Cow : public Animal {
public:
    void Speak() override {
        std::cout << "Cow: 哞哞哞" << std::endl;
    }
};

void Speak(shared_ptr<Animal> animal)
{
    animal->Speak();
}

int main() { 

    IocContainer<Animal> ioc;

    // 注册对象类型与字符串的映射关系
    ioc.RegisterType<Dog>("Dog");
    ioc.RegisterType<Cat>("Cat");
    ioc.RegisterType<Cow>("Cow");

    // 从配置文件中获取需要构建的对象配置

    auto dog = ioc.ResolveShared("Dog");
    Speak(dog);
    auto cat = ioc.ResolveShared("Cat");
    Speak(cat);
    auto cow = ioc.ResolveShared("Cow");
    Speak(cow);

    return 0;
}
